package models.util;

import java.util.Random;
import java.util.concurrent.TimeUnit;

import controllers.games.PallonciniMatematiciController;
import models.games.PallonciniMatematici;
import views.games.PallonciniMatematiciView;

public class BalloonThread extends Thread {

	private PallonciniMatematici game;// gioco condiviso dai thread
	private int operand1, operand2, result;
	private Operation operation;
	private Velocity velocity;
	private int slot;
	private PallonciniMatematiciView view;
	private PallonciniMatematiciController controller;

	private Random random = new Random();
	private int TIME;// tempo di vita del thread; dipende dalla Velocity

	enum Operation {
		SUM, SUBTRACTION, PRODUCT
	};

	public enum Velocity {
		LOW, MEDIUM_LOW, MEDIUM, MEDIUM_HIGH, HIGH
	};

	public void setView(PallonciniMatematiciView v) {
		view = v;
	}

	public void setController( PallonciniMatematiciController c){
		controller = c;
	}
	
	public BalloonThread(Velocity velocity, PallonciniMatematici p, int s) {
		slot = s;
		game = p;
		operand1 = randomOperand();
		operand2 = randomOperand();
		operation = randomOperation();
		// eventuale inversione degli operandi per evitare risultati negativi
		if (operation == Operation.SUBTRACTION && operand1 < operand2) {
			int tmp = operand1;
			operand1 = operand2;
			operand2 = tmp;
		}
		// eventuale troncamento del secondo operando se a due cifre per evitare
		// calcoli troppo complessi
		if (operation == Operation.PRODUCT && operand2 > 10) {
			operand2 = operand2 / 10;
		}
		result = calculateResult();
		this.velocity = velocity;
		TIME = getDuration();
	}

	public int getDuration() {
		return (5 - velocity.ordinal()) * 4;
	}

	public int getSlot() {
		return slot;
	}

	/**
	 * @return il risultato associato al pallocino
	 */
	public int getResult() {
		return result;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Thread#run() Il Thread dorme per TIME secondi. L'uscita
	 * tramite exception indica che il palloncino è stato esploso in tempo.
	 * Altrimenti si ha l'esplosione del palloncino dovuta al contatto col piano
	 * spinoso.
	 */
	public void run() {
		try {
			System.out.println("Tempo di salita: " + TIME + " secondi");
			TimeUnit.SECONDS.sleep(TIME);
		} catch (InterruptedException e) {
			System.out.println("Palloncino " + toString() + " esploso");
			game.releaseSlot(slot);
			view.removeBalloon(slot);
			return;
		}
		game.releaseSlot(slot);
		view.removeBalloon(slot);
		try {
			game.explodeAll();
			controller.updateRemainingErrors();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	@Override
	public String toString() {
		String op;
		switch (operation) {
		case SUM:
			op = "+";
			break;
		case SUBTRACTION:
			op = "-";
			break;
		default:
			op = "x";
		}
		return "" + operand1 + op + operand2;
	}

	@Override
	public int hashCode() {
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		BalloonThread balloon = (BalloonThread) obj;
		if (result != balloon.result)
			return false;
		return true;
	}

	/**
	 * @return il risultato dell'operazione associata al palloncino
	 */
	private int calculateResult() {
		switch (operation) {
		case SUM:
			return operand1 + operand2;
		case SUBTRACTION:
			return operand1 - operand2;
		default:
			return operand1 * operand2;
		}
	}

	/**
	 * @return una operazione casuale
	 */
	private Operation randomOperation() {
		int op = random.nextInt(3);
		switch (op) {
		case 0:
			return Operation.SUM;
		case 1:
			return Operation.SUBTRACTION;
		default:
			return Operation.PRODUCT;
		}
	}

	/**
	 * @return un operando casuale
	 */
	private int randomOperand() {
		return random.nextInt(40);
	}

}
